#include"fs/fs.h"
#include"tools/klib.h"
#include"comm/types.h"
#include<sys/stat.h>
#include"tools/log.h"
#include"dev/console.h"
#include"comm/cpu_instr.h"
#include"tools/list.h"
#include"fs/devfs/devfs.h"
#include"dev/disk.h"
#include<sys/file.h>
#include"os_cfg.h"


//设备文件系统
extern fs_op_t devfs_op;
//fat16文件系统
extern fs_op_t fatfs_op;

static fs_t* root_fs;

#define FS_TABLE_SIZE  10

static list mounted_list;
static fs_t fs_table[FS_TABLE_SIZE];
static list free_list;

// #define TEMP_ADDR  (8*1024*1024)      // 在0x800000处缓存原始
// static uint8_t * temp_pos;       // 当前位置

// #define TEMP_FILE_ID 100

// //读磁盘
// static void read_disk(int sector, int sector_count, uint8_t * buf) 
// {
//     outb(0x1F6, (uint8_t) (0xE0));

// 	outb(0x1F2, (uint8_t) (sector_count >> 8));
//     outb(0x1F3, (uint8_t) (sector >> 24));		// LBA参数的24~31位
//     outb(0x1F4, (uint8_t) (0));					// LBA参数的32~39位
//     outb(0x1F5, (uint8_t) (0));					// LBA参数的40~47位

//     outb(0x1F2, (uint8_t) (sector_count));
// 	outb(0x1F3, (uint8_t) (sector));			// LBA参数的0~7位
// 	outb(0x1F4, (uint8_t) (sector >> 8));		// LBA参数的8~15位
// 	outb(0x1F5, (uint8_t) (sector >> 16));		// LBA参数的16~23位

// 	outb(0x1F7, (uint8_t) 0x24);

// 	// 读取数据
// 	uint16_t *data_buf = (uint16_t*) buf;
// 	while (sector_count-- > 0) 
//     {
// 		// 每次扇区读之前都要检查，等待数据就绪
// 		while ((inb(0x1F7) & 0x88) != 0x8) 
//         {}

// 		// 读取并将数据写入到缓存中
// 		for (int i = 0; i < SECTOR_SIZE / 2; i++) 
//         {
// 			*data_buf++ = inw(0x1F0);
// 		}
// 	}
// }

//判断路径是否有效
static int is_path_valid (const char * path) 
{
	if ((path == (const char *)0) || (path[0] == '\0')) {
		return 0;
	}

    return 1;
}


static int is_fd_bad (int file) 
{
	if ((file < 0) && (file >= TASK_OPENFILE_SIZE)) 
	{
		return 1;
	}

	return 0;
}

//获取下一级子目录
const char * path_next_child (const char * path) 
{
   const char * c = path;

    while (*c && (*c++ == '/')) {}
    while (*c && (*c++ != '/')) {}
    return *c ? c : (const char *)0;
}

//转换目录为数字
int path_to_num (const char * path, int * num) 
{
	int n = 0;

	const char * c = path;
	while (*c && *c != '/') {
		n = n * 10 + *c - '0';
		c++;
	}
	*num = n;
	return 0;
}

int path_begin_with (const char * path, const char * str) 
{
	const char * s1 = path, * s2 = str;
	while (*s1 && *s2 && (*s1 == *s2)) {
		s1++;
		s2++;
	}

	return *s2 == '\0';
}

static void fs_protect (fs_t * fs) 
{
	if (fs->mutex) 
	{
		mutex_lock(fs->mutex);
	}
}

static void fs_unprotect (fs_t * fs) 
{
	if (fs->mutex) 
	{
		mutex_unlock(fs->mutex);
	}
}

int sys_open(const char *name, int flags, ...)
{
	// // 临时使用，保留shell加载的功能
	// if (kernel_strncmp(name, "/shell.elf", 4) == 0) 
	// {
    //     //直接从扇区1000上读取, 读取大概40KB，足够了
    //     // read_disk(5000, 80, (uint8_t *)TEMP_ADDR);
	// 	int dev_id = dev_open(DEV_DISK,0xa0,(void*)0);
    //     dev_read(dev_id,5000,(uint8_t*)TEMP_ADDR,80);
	// 	temp_pos=(uint8_t*)TEMP_ADDR;
    //     return TEMP_FILE_ID;
    // }

	file_t * file = file_alloc();
	if (!file) 
	{
		return -1;
	}

	int fd = task_alloc_fd(file);
	if (fd < 0) 
	{
		goto sys_open_failed;
	}

	// 检查名称是否以挂载点开头，如果没有，则认为name在根目录下
	// 即只允许根目录下的遍历
	fs_t * fs = (fs_t *)0;
	list_node * node = list_first(&mounted_list);
	while (node) 
	{
		fs_t * curr = list_node_parent(node, fs_t, node);
		if (path_begin_with(name, curr->mount_point)) 
		{
			fs = curr;
			break;
		}
		node = list_node_next(node);
	}

	if (fs) 
	{
		name = path_next_child(name);
	} else 
	{
		fs = root_fs;
	}

	file->mode = flags;
	file->fs = fs;
	kernel_strncpy(file->file_name, name, FILE_NAME_SIZE);

	fs_protect(fs);
	int err = fs->op->open(fs, name, file);
	if (err < 0) 
	{
		fs_unprotect(fs);
		print_log("open %s failed.", name);
		return -1;
	}
	fs_unprotect(fs);

	return fd;

sys_open_failed:
	file_free(file);
	if (fd >= 0) 
	{
		task_remove_fd(fd);
	}
	return -1;
}


int sys_read(int file, char* ptr, int len)
{
//    if (file == TEMP_FILE_ID) 
//    {
//         kernel_memcpy(ptr, temp_pos, len);
//         temp_pos += len;
//         return len;
//     }

    if (is_fd_bad(file) || !ptr || !len) 
	{
		return 0;
	}

	file_t * p_file = task_file(file);
	if (!p_file) 
	{
		print_log("file not opened");
		return -1;
	}

	if (p_file->mode == O_WRONLY) 
	{
		print_log("file is write only");
		return -1;
	}

	// 读取文件
	fs_t * fs = p_file->fs;
	fs_protect(fs);
	int err = fs->op->read(ptr, len, p_file);
	fs_unprotect(fs);
	return err;
}

int sys_write(int file, char *ptr, int len)
{
	if (is_fd_bad(file) || !ptr || !len) 
	{
		return 0;
	}

	file_t * p_file = task_file(file);
	if (!p_file) 
	{
		print_log("file not opened");
		return -1;
	}

	if (p_file->mode == O_RDONLY) 
	{
		print_log("file is write only");
		return -1;
	}

	// 写入文件
	fs_t * fs = p_file->fs;
	fs_protect(fs);
	int err = fs->op->write(ptr, len, p_file);
	fs_unprotect(fs);
	return err;
}

int sys_lseek(int file, int ptr, int dir)
{
    // if (file == TEMP_FILE_ID) 
	// {
    //     temp_pos = (uint8_t *)(ptr + TEMP_ADDR);
    //     return 0;
    // }

	if (is_fd_bad(file)) 
	{
		return -1;
	}

	file_t * p_file = task_file(file);
	if (!p_file) 
	{
		print_log("file not opened");
		return -1;
	}

	// 写入文件
	fs_t * fs = p_file->fs;

	fs_protect(fs);
	int err = fs->op->seek(p_file, ptr, dir);
	fs_unprotect(fs);
	return err;
}

int sys_close(int file)
{
    // if (file == TEMP_FILE_ID) 
	// {
	// 	return 0;
	// }

	if (is_fd_bad(file)) 
	{
		print_log("file error");
		return -1;
	}

	file_t * p_file = task_file(file);
	if (p_file == (file_t *)0) 
	{
		print_log("file not opened. %d", file);
		return -1;
	}

	ASSERT(p_file->ref > 0);

	if (p_file->ref-- == 1) 
	{
		fs_t * fs = p_file->fs;

		fs_protect(fs);
		fs->op->close(p_file);
		fs_unprotect(fs);
	    file_free(p_file);
	}

	task_remove_fd(file);
	return 0;
}

int sys_unlink(const char* path)
{
	fs_protect(root_fs);
	int err = root_fs->op->unlink(root_fs,path);
	fs_unprotect(root_fs);
	return err;
}



int sys_ioctl(int fd, int cmd, int arg0, int arg1) 
{
	if (is_fd_bad(fd)) 
	{
		return 0;
	}

	file_t * pfile = task_file(fd);
	if (pfile == (file_t *)0) 
	{
		return 0;
	}

	fs_t * fs = pfile->fs;

	fs_protect(fs);
	int err = fs->op->ioctl(pfile, cmd, arg0, arg1);
	fs_unprotect(fs);
	return err;
}








int sys_isatty(int file)
{
    return -1;
}

int sys_fstat(int file,struct stat* st)
{
    return -1;
}




int sys_dup (int fd) 
{
	if ((fd < 0) && (fd >= TASK_OPENFILE_SIZE)) 
	{
        print_log("file(%d) is not valid.", fd);
		return -1;
	}

	file_t * p_file = task_file(fd);
	if (!p_file) 
	{
		print_log("file not opened");
		return -1;
	}

	int new_fd = task_alloc_fd(p_file);	// 新fd指向同一描述符
	if (new_fd >= 0) 
	{
		p_file->ref++;		// 增加引用
		return new_fd;
	}

	print_log("No task file avaliable");
    return -1;
}


//获取指定文件系统的操作接口
static fs_op_t * get_fs_op (fs_type_t type, int major) 
{
	switch (type) 
	{
		case FS_DEVFS:
			return &devfs_op;
		case FS_FAT16:
			return &fatfs_op;
		default:
			return (fs_op_t *)0;
	}
}



//挂载文件系统
static fs_t * mount (fs_type_t type, char* mount_point, int dev_major, int dev_minor)
{
	fs_t * fs = (fs_t *)0;
	print_log("mount file system, name: %s, dev: %x", mount_point, dev_major);

	// 遍历，查找是否已经有挂载
 	list_node * curr = list_first(&mounted_list);
	while (curr) 
	{
		fs_t * fs = list_node_parent(curr, fs_t, node);
		if (kernel_strncmp(fs->mount_point, mount_point, FS_MOUNTP_SIZE) == 0) 
		{
			print_log("fs alreay mounted.");
			goto mount_failed;
		}
		curr = list_node_next(curr);
	}

	// 分配新的fs结构
	list_node * free_node = list_remove_first(&free_list);
	if (!free_node) 
	{
		print_log("no free fs, mount failed.");
		goto mount_failed;
	}

	fs = list_node_parent(free_node, fs_t, node);

	// 检查挂载的文件系统类型
	fs_op_t * op = get_fs_op(type, dev_major);
	if (!op) 
	{
		print_log("unsupported fs type: %d", type);
		goto mount_failed;
	}

	// 给定数据一些缺省的值
	kernel_memset(fs, 0, sizeof(fs_t));
	kernel_strncpy(fs->mount_point, mount_point, FS_MOUNTP_SIZE);

	fs->op = op;
	fs->mutex = (mutex_t *)0;

	// 挂载文件系统
	if (op->mount(fs,dev_major, dev_minor) < 0) 
	{
		print_log("mount fs %s failed", mount_point);
		goto mount_failed;
	}
	list_insert_last(&mounted_list, &fs->node);
	return fs;
mount_failed:
	if (fs) 
	{
		// 回收fs
		list_insert_first(&free_list, &fs->node);
	}
	return (fs_t *)0;
}



//初始化挂载列表
static void mount_list_init (void) 
{
	list_init(&free_list);
	for (int i = 0; i < FS_TABLE_SIZE; i++) 
	{
		list_insert_first(&free_list, &fs_table[i].node);
	}
	list_init(&mounted_list);
}


void fs_init()
{
	mount_list_init();
	//文件列表初始化
    file_table_init();

	//磁盘初始化
	disk_init();

	// 挂载设备文件系统
	fs_t * fs = mount(FS_DEVFS, "/dev", 0, 0);

	// 挂载fat文件系统   只挂载 0xb1 分区
	root_fs = mount(FS_FAT16,"/home",ROOT_DEV);


	ASSERT(fs != (fs_t *)0);
	ASSERT(root_fs != (fs_t *)0);
}


int sys_opendir(const char * name, DIR * dir) 
{
	fs_protect(root_fs);
	int err = root_fs->op->opendir(root_fs, name, dir);
	fs_unprotect(root_fs);
	return err;
}

int sys_readdir(DIR* dir, struct dirent * dirent) 
{
	fs_protect(root_fs);
	int err = root_fs->op->readdir(root_fs, dir, dirent);
	fs_unprotect(root_fs);
	return err;
}

int sys_closedir(DIR *dir) 
{
	fs_protect(root_fs);
	int err = root_fs->op->closedir(root_fs, dir);
	fs_unprotect(root_fs);
	return err;
}
